﻿Option Explicit On
Imports System.Xml

Public Class frmEditGems
    ' James D. Zoll
    '
    ' The Edit Gems form shows a form to the user that allows
    ' editing of the master gems list of gems available. Gems are loaded
    ' from the main form rather than the file, since they are loaded when
    ' the program is run.  When editing is complete the gems are saved back
    ' to data_gems.xml and the main form is instructed to reload from the file
    ' to make sure everything is correct on the main form.

    ' Variables to hold the gems and the number of gems.
    Dim gems() As Gem
    Dim numGems As Integer

    ' Variables to help with the save state.
    Private t_gemName As String
    Private saved As Boolean

    ' The event that is raised the gem editing is complete
    ' that allows the main form to re-load gems.
    Public Event EditGemsComplete()

    Public Sub EditGemSetup()
        ' This function is called from the parent form to set the
        ' grid to the correct size and headers and to also setup
        ' the various checkboxes and dropdowns that need to be in 
        ' place for the grid to function correctly.

        ' Basis loop variable declaration
        Dim loopvar As Integer

        ' Gem number initialization.
        numGems = 0

        ' Grid formatting
        grdGems.AutoRedraw = False
        grdGems.Cols = 13
        grdGems.Rows = 2
        grdGems.ExtendLastCol = True
        grdGems.Column(0).Visible = False
        grdGems.BoldFixedCell = False
        grdGems.Cell(0, 1).Text = "Gem Name"
        grdGems.Cell(0, 2).Text = "Color"
        grdGems.Cell(0, 3).Text = "Str"
        grdGems.Cell(0, 4).Text = "AP"
        grdGems.Cell(0, 5).Text = "Crit"
        grdGems.Cell(0, 6).Text = "Haste"
        grdGems.Cell(0, 7).Text = "ArP"
        grdGems.Cell(0, 8).Text = "Agi"
        grdGems.Cell(0, 9).Text = "Exp"
        grdGems.Cell(0, 10).Text = "Hit"
        grdGems.Cell(0, 11).Text = "JC Gem"
        grdGems.Column(11).Visible = False
        For loopvar = 3 To grdGems.Cols - 1
            grdGems.Column(loopvar).Width = 40
        Next
        grdGems.Column(1).Width = 170
        grdGems.Column(2).Width = 75
        grdGems.Column(11).Width = 50
        grdGems.Column(2).CellType = FlexCell.CellTypeEnum.ComboBox
        grdGems.ComboBox(2).Items.Clear()
        grdGems.ComboBox(2).Items.Add("None")
        grdGems.ComboBox(2).Items.Add("Red")
        grdGems.ComboBox(2).Items.Add("Yellow")
        grdGems.ComboBox(2).Items.Add("Blue")
        grdGems.ComboBox(2).Items.Add("Orange")
        grdGems.ComboBox(2).Items.Add("Green")
        grdGems.ComboBox(2).Items.Add("Purple")
        grdGems.ComboBox(2).Items.Add("Prismatic")
        grdGems.Column(11).CellType = FlexCell.CellTypeEnum.ComboBox
        grdGems.ComboBox(11).Items.Clear()
        grdGems.ComboBox(11).Items.Add("No")
        grdGems.ComboBox(11).Items.Add("Yes")
        grdGems.Column(12).CellType = FlexCell.CellTypeEnum.ComboBox
        grdGems.ComboBox(12).Items.Clear()
        grdGems.ComboBox(12).Items.Add("No")
        grdGems.ComboBox(12).Items.Add("Yes")
        grdGems.AutoRedraw = True
        grdGems.Refresh()

        ' Saved flag set to true.
        setSaved(True)

    End Sub

    Public Sub AddGem(ByVal inGem As Gem)
        ' This sub adds a gem to the array of editable gems
        ' for this form.  It is called once for each gem on the main
        ' form so that all gems are present on the Edit Gems form.
        numGems += 1
        ReDim Preserve gems(0 To numGems - 1)
        gems(numGems - 1) = inGem.clone
    End Sub

    Public Sub DisplayGems()
        ' Iterate through all gems and display them on the current
        ' flexcell grid for this form.  This uses the method
        ' .showStatic which is internal to the Gem class.

        ' Basic loop variable declaration
        Dim loopvar As Integer

        ' Format the grid and show each gem.
        grdGems.Rows = numGems + 1
        For loopvar = 0 To numGems - 1
            gems(loopvar).showStatic(grdGems, loopvar + 1, 1)
        Next
    End Sub

    Private Function ChangeProperty(ByVal gemName As String, ByVal col As Integer, ByVal row As Integer) As Integer
        ' When a property is changed and verified by the rest of the class,
        ' this function is called to change that property in the underlying gem array.
        ' The function returns the index of the gem which is found through iterative name looping.

        ' Loop and control variable declaration.
        Dim gemIndex As Integer
        Dim loopvar As Integer
        Dim newProp As String

        ' Iterate through the array to find the appropriate index.
        For loopvar = 0 To UBound(gems)
            If gems(loopvar).name = gemName Then
                gemIndex = loopvar
            End If
        Next

        ' Find the new value of the property and do the correct
        ' formatting to apply it to the gem array.
        newProp = grdGems.Cell(row, col).Text
        With gems(gemIndex)
            Select Case col
                Case 1
                    If .name <> newProp Then setSaved(False)
                    .name = newProp
                Case 2
                    If .getColor <> newProp Then setSaved(False)
                    .setColor(newProp)
                Case 3
                    If .str <> Double.Parse(newProp) Then setSaved(False)
                    .str = Double.Parse(newProp)
                Case 4
                    If .ap <> Double.Parse(newProp) Then setSaved(False)
                    .ap = Double.Parse(newProp)
                Case 5
                    If .crit <> Double.Parse(newProp) Then setSaved(False)
                    .crit = Double.Parse(newProp)
                Case 6
                    If .haste <> Double.Parse(newProp) Then setSaved(False)
                    .haste = Double.Parse(newProp)
                Case 7
                    If .arp <> Double.Parse(newProp) Then setSaved(False)
                    .arp = Double.Parse(newProp)
                Case 8
                    If .agi <> Double.Parse(newProp) Then setSaved(False)
                    .agi = Double.Parse(newProp)
                Case 9
                    If .exp <> Double.Parse(newProp) Then setSaved(False)
                    .exp = Double.Parse(newProp)
                Case 10
                    If .hit <> Double.Parse(newProp) Then setSaved(False)
                    .hit = Double.Parse(newProp)
                Case 11
                    If .getJCGem_YN <> newProp Then setSaved(False)
                    If newProp = "Yes" Then
                        .jcgem = True
                    Else
                        .jcgem = False
                    End If
                Case 12
                    If .getUnique_YN <> newProp Then setSaved(False)
                    If newProp = "Yes" Then
                        .unique = True
                    Else
                        .unique = False
                    End If
            End Select
        End With

        ' Return the array index of the changed gem.
        ChangeProperty = gemIndex

    End Function

    Private Sub grdGems_LeaveCell(ByVal Sender As Object, ByVal e As FlexCell.Grid.LeaveCellEventArgs) Handles grdGems.LeaveCell
        ' This subroutine manages the verification of data as it is entered in cells on the grid.
        ' If an invalid value is entered, the user is informed and focus is returned to the invalid
        ' cell.  If a valid value is entered, focus is permitted to leave and the underlying array
        ' is updated.

        ' Control variable declaration
        Dim curGemIndex As Integer
        Dim nameString As String

        ' Cells are set to default values if left empty by the user.
        ' These will always pass validation.
        If grdGems.ActiveCell.Row = 0 Then Exit Sub
        If grdGems.ActiveCell.Text = "" Then
            Select Case grdGems.ActiveCell.Col
                Case 1
                    grdGems.ActiveCell.Text = ""
                Case 2
                    grdGems.ActiveCell.Text = "None"
                Case 3 To 10
                    grdGems.ActiveCell.Text = "0"
                Case 11, 12
                    grdGems.ActiveCell.Text = "No"
            End Select
        End If

        ' Determine via a function if the cell contains a valid
        ' value.  If invalid then inform the user and return focus
        ' to the cell.  If valid then do the property switching.
        If isValidValue(grdGems.ActiveCell) = False Then
            If grdGems.ActiveCell.Col <> 1 Then
                MessageBox.Show("Invalid Cell Value. Please enter a different value.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            Else
                MessageBox.Show("Duplicate name exists.  Please enter a different name.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            End If
            e.Cancel = True
        Else
            If e.Col = 1 Then
                nameString = t_gemName
            Else
                nameString = grdGems.Cell(grdGems.ActiveCell.Row, 1).Text
            End If
            curGemIndex = ChangeProperty(nameString, grdGems.ActiveCell.Col, grdGems.ActiveCell.Row)
            If e.Col = 2 Then
                grdGems.Cell(grdGems.ActiveCell.Row, 2).BackColor = gems(curGemIndex).RGBColor
            End If
        End If

    End Sub

    Private Sub grdGems_RowColChange(ByVal Sender As Object, ByVal e As FlexCell.Grid.RowColChangeEventArgs) Handles grdGems.RowColChange
        ' When the row or column changes of the grid, it is important
        ' to preserve the name of the gem if the user is altering it, since
        ' this is used to key into the gem array as the underlying strucure.
        If grdGems.ActiveCell.Col = 1 Then
            t_gemName = grdGems.ActiveCell.Text
        End If
    End Sub

    Private Function isValidValue(ByVal cell As FlexCell.Cell) As Boolean
        ' The function returns a boolean representing whether or not the value 
        ' of a passed cell is valid for the column that it inhabits.

        ' If the row is zero (the header), then we shouldn't really be here.
        ' However, just in case we will return true and exit the function.
        If cell.Row = 0 Then
            isValidValue = True
            Exit Function
        End If

        ' Based on the column, check the value and then return the appropriate
        ' response.
        Select Case cell.Col
            Case 0
                isValidValue = True
            Case 1
                Dim loopvar As Integer
                For loopvar = 1 To grdGems.Rows - 1
                    If grdGems.Cell(loopvar, 1).Text = cell.Text And loopvar <> cell.Row Then
                        isValidValue = False
                        Exit Function
                    End If
                Next
                isValidValue = True
            Case 2
                If cell.Text <> "Red" And cell.Text <> "Yellow" And cell.Text <> "Blue" And _
                    cell.Text <> "Orange" And cell.Text <> "Green" And cell.Text <> "Purple" And _
                    cell.Text <> "None" And cell.Text <> "Prismatic" Then
                    isValidValue = False
                Else
                    isValidValue = True
                End If
            Case 3 To 10
                If IsNumeric(cell.Text) = False Or Double.Parse(cell.Text) < 0 Or Double.Parse(cell.Text) > 10000 Then
                    isValidValue = False
                Else
                    isValidValue = True
                End If
            Case 11, 12
                If cell.Text = "Yes" Or cell.Text = "No" Then
                    isValidValue = True
                Else
                    isValidValue = False
                End If
            Case Else
                isValidValue = False
        End Select
    End Function

    Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
        ' This procedure adds a gem to both the underlying array and the displayed grid.
        ' The new gem has a name taken from an inputbox while all other values are the
        ' defaults of zero / false / etc.

        ' Control variables
        Dim inputResult As String
        Dim loopvar As Integer

        ' Attempt to move focus.  If the active cell is invalid
        ' this will fail, and the sub will exit for a correction
        ' to be made.
        grdGems.Cell(grdGems.ActiveCell.Row, 0).SetFocus()
        If grdGems.ActiveCell.Col <> 0 Then Exit Sub

        ' Prompt for the new name.  Check the validity and if a valid name was chosen
        ' and cancel was not hit, then add the new gem.
        inputResult = InputBox("Please enter a name for the new Gem:", "DK Optimize")
        If inputResult <> "" Then
            For loopvar = 0 To numGems - 1
                If gems(loopvar).name = inputResult Then
                    MessageBox.Show("Gem name already exists.  Please select a different name.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
                    Exit Sub
                End If
            Next
            Dim tempGem As Gem
            tempGem = New Gem
            tempGem.clear()
            tempGem.name = inputResult
            numGems += 1
            ReDim Preserve gems(0 To numGems - 1)
            gems(UBound(gems)) = tempGem
            grdGems.Rows += 1
            gems(UBound(gems)).showStatic(grdGems, grdGems.Rows - 1, 1)
            setSaved(False)
        End If

    End Sub

    Private Sub btnDel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDel.Click
        ' This function will delete (after a verification prompt) a gem from
        ' both the displayed grid and the underlying gem array.

        ' Control variables for looping and message box results.
        Dim msgResult As DialogResult
        Dim loopvar As Integer
        Dim curGemIndex As Integer

        ' Attempt to leave the current cell.  If unable it means
        ' that the control failed verification and requires the focus.
        grdGems.Cell(grdGems.ActiveCell.Row, 0).SetFocus()
        If grdGems.ActiveCell.Col <> 0 Then Exit Sub

        ' If we have nothing selected then exit the sub
        ' as there is nothing to delete.
        If grdGems.ActiveCell.Row = 0 Then Exit Sub

        ' Prompt the user as verification.  If the user confirms, then iterate through
        ' and delete from both the gem array and the grid
        msgResult = MessageBox.Show("Are you sure you want to delete """ & grdGems.Cell(grdGems.ActiveCell.Row, 1).Text & """?", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
        If msgResult = Windows.Forms.DialogResult.No Then Exit Sub
        For loopvar = 0 To UBound(gems)
            If gems(loopvar).name = grdGems.Cell(grdGems.ActiveCell.Row, 1).Text Then
                curGemIndex = loopvar
            End If
        Next
        grdGems.RemoveItem(grdGems.ActiveCell.Row)
        For loopvar = curGemIndex To UBound(gems) - 1
            gems(loopvar) = gems(loopvar + 1)
        Next
        numGems -= 1
        ReDim Preserve gems(0 To numGems - 1)

        ' A gem is gone, so set the saved flag to false.
        setSaved(False)

    End Sub

    Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
        ' This handles logic for when the save button is clicked.
        ' After verifying that the user wishes to save,
        ' the function calls saveGems, which writes out to the XML file
        ' containing the gem information.

        ' Control variable declaration.
        Dim msgResult As DialogResult

        ' Attempt to move focus away from the current cell to
        ' force validation.  If it fails, do not save since
        ' there is an invalid value on the grid.
        grdGems.Cell(grdGems.ActiveCell.Row, 0).SetFocus()
        If grdGems.ActiveCell.Col <> 0 Then Exit Sub

        ' Prompt the user
        msgResult = MessageBox.Show("Are you sure you want to save all gems?", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
        If msgResult = Windows.Forms.DialogResult.No Then Exit Sub

        ' Save the gems and set the flag to true.
        saveGems()
        setSaved(True)

    End Sub

    Private Sub saveGems()
        ' This procedure opens data_gems.xml in the CommonAppDataPath forlder
        ' and writes out the information in the gems() array to the file
        ' in XML format.

        ' Variable declaration for control and for the
        ' xmlWriter.
        Dim loopvar As Integer
        Dim xmlWriter As New XmlTextWriter(Windows.Forms.Application.CommonAppDataPath & "\data_gems.xml", System.Text.Encoding.UTF8)
        Dim buildInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)

        ' Write the file, iterating all gems.
        xmlWriter.WriteStartDocument()
        xmlWriter.WriteWhitespace(vbNewLine)
        xmlWriter.WriteStartElement("gems")
        xmlWriter.WriteAttributeString("version", buildInfo.ProductVersion)
        For loopvar = 0 To UBound(gems)
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab)
            xmlWriter.WriteStartElement("gem")
            xmlWriter.WriteAttributeString("name", gems(loopvar).name)
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("color", gems(loopvar).getColor)
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("str", gems(loopvar).str.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("ap", gems(loopvar).ap.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("crit", gems(loopvar).crit.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("haste", gems(loopvar).haste.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("arp", gems(loopvar).arp.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("agi", gems(loopvar).agi.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("exp", gems(loopvar).exp.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("hit", gems(loopvar).hit.ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("jcgem", gems(loopvar).jcgem)
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab & vbTab)
            xmlWriter.WriteElementString("unique", gems(loopvar).unique)
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteWhitespace(vbTab)
            xmlWriter.WriteEndElement()
        Next
        xmlWriter.WriteWhitespace(vbNewLine)
        xmlWriter.WriteEndElement()
        xmlWriter.WriteEndDocument()
        xmlWriter.Close()
    End Sub

    Private Sub setSaved(ByVal state As Boolean)
        ' Toggle the state of the saved flag
        ' and set the form caption accordingly.
        If state = True Then
            saved = True
            Me.Text = "DK Optimize - Edit Gems"
        Else
            saved = False
            Me.Text = "DK Optimize - Edit Gems*"
        End If
    End Sub

    Private Sub frmEditGems_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        ' Checked saved, warn the user, cancel if they don't want to go.
        Dim msgresult As DialogResult

        grdGems.Cell(grdGems.ActiveCell.Row, 0).SetFocus()

        ' If there was an error, activecell will still have a value.
        If grdGems.ActiveCell.Col <> 0 Then
            e.Cancel = True
            Exit Sub
        End If

        If saved = False Then
            msgresult = MessageBox.Show("Gems are not saved.  Would you like to save Gem information?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            Select Case msgresult
                Case Windows.Forms.DialogResult.Cancel
                    e.Cancel = True
                Case Windows.Forms.DialogResult.Yes
                    saveGems()
                    setSaved(True)
                    e.Cancel = False
                    Me.Hide()
                    RaiseEvent EditGemsComplete()
                Case Windows.Forms.DialogResult.No
                    e.Cancel = False
                    Me.Hide()
                    RaiseEvent EditGemsComplete()
            End Select
        Else
            e.Cancel = False
            Me.Hide()
            RaiseEvent EditGemsComplete()
        End If

    End Sub
End Class